/******************************************************************/
/* 				MOLPROC.C						*/
/* 											*/
/******************************************************************/

/*---------------------- LINUX HEADERS ---------------------------*/
#define _GNU_SOURCE 
#include <stdio.h>
#include <stdint.h> 
#include <dlfcn.h> 
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


/*---------------------- MINIX HEADERS ---------------------------*/

#include "../include/minix/config.h" 	
#include "../include/minix/endpoint.h" 	
#include "../../kernel/ipc.h"			

/* #include "../../kernel/const.h"  	*/
/* #include "../../kernel/type.h"		*/
/* #include "../../kernel/priv.h"		*/
/* #include "../../kernel/com.h"		*/
/* #include "../../kernel/endpoint.h"	*/

/*---------------------- MOL HEADERS -----------------------------*/
#include "../include/mol/molminix.h" 
#define MOLDBG 1
#include "../include/mol/mollib.h" 
#define _SYSTEM
#include "../include/mol/molerr.h" 

/*---------------------- MOLMINIX HEADERS -------------------------*/
#include "molproc.h"
#include "proc.h"
#include "svripc.h"

/*---------------------- GLOBAL VARIABLES  ----------------------*/
extern ipc_t 		mk_ipc;		/* defines IPC struct	*/
extern struct kproc	kproc[];		/* kernel process table */
extern pid_t		kpid;			/* spid of MOLMINIX	*/

/*----------------------------------------------------------*/
/*			mol_mini_send					*/
/* SEND request received						*/
/*----------------------------------------------------------*/
int mol_mini_send(ipc_t *pipc)
{
	struct kproc *sptr, *dptr;
	struct kproc *xpp;
	int rcode;
	proc_nr_t dst_p, src_p;

OLDEBUG("code=%X spid=%d seq=%d p_nr=%d p_endpoint=%d srcdst=%d m_source=%d\n",
                pipc->molmsg.code,
                pipc->molmsg.spid,
                pipc->molmsg.seq,
                pipc->molmsg.p_nr,
                pipc->molmsg.p_endpoint,
                pipc->molmsg.srcdst,
                pipc->molmsg.mnxmsg.m_source);
	
	/* Check sender's endpoint			 	*/
	src_p = check_endpoint(pipc->molmsg.p_endpoint);
	if( src_p == NONE )
		MOLERROR("Bad source endpoint rcode=%d\n",src_p);
	sptr = &kproc[src_p+NR_TASKS];		

	/* Check if the sender is a registered process 	*/
	rcode = check_registered(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks for valid received sequence 		*/
	rcode = check_sequence(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks if the sender == destination		*/
	rcode = check_sameproc(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks if the sender process is NOTREADY	*/
	rcode = check_notready(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Check destination's endpoint		 	*/
	dst_p = check_endpoint(pipc->molmsg.srcdst);
	if( dst_p == NONE )
		MOLERROR("Bad destination endpoint rcode=%d\n",dst_p);
	dptr = &kproc[dst_p+NR_TASKS];
		
	/* Check if the destination is a registered process */
	rcode = check_registered(dptr, pipc);
	if( rcode != OK) return(rcode);

	if ( (dptr->p_rts_flags & (RECEIVING | SENDING)) == RECEIVING &&
       	(dptr->p_getfrom_e == ANY  || 
         	dptr->p_getfrom_e == sptr->p_endpoint)) 
		{
		/*------------ The destination process is waiting for this message	*/

		dptr->p_rts_flags &= ~RECEIVING;	/* unblock destination 	*/

		/* build the MOL HEADER to send to the DESTINATION		*/
		pipc->molmsg.code = (RECEIVE | ACKNOWLEDGE) ;
		pipc->molmsg.spid = kpid;
		pipc->molmsg.seq  = dptr->kseq;
		memcpy((void*)&pipc->addr, (void*)&dptr->ipc_addr, (sizeof(struct sockaddr)));

OLDEBUG("Minix message m_type=%d\n",dptr->messbuf.m_type);
		/* the MINIX message is already in the IPC received struct 	*/
		/* send the MESSAGE to the DESTINATION				*/
		rcode = svr_send(pipc);
		if( rcode != OK)
			MOLERROR("svr_send to DESTINATION rcode=%d\n",rcode);
			
		/* prepare the MOL HEADER to send ACK to the SENDER		*/
		pipc->molmsg.code = (SEND | ACKNOWLEDGE) ;
		pipc->molmsg.spid = kpid;
		pipc->molmsg.seq  = sptr->kseq;
		memcpy((void*)&pipc->addr,(void*)&sptr->ipc_addr,(sizeof(struct sockaddr)));

		/* send the ACKNOWLEDGE to the SENDER				*/
		rcode = svr_send(pipc);
		if( rcode != OK)
			MOLERROR("svr_send to SENDER rcode=%d\n",rcode);

		if ( dptr->p_rts_flags != 0)
			MOLERROR("DESTINATION flags = %X\n", dptr->p_rts_flags );
		}
	else
		{
		/*----- The destination process is NOT waiting for this message	*/

		/* block the sender								*/
		sptr->p_rts_flags |= SENDING;

		/* set the wanted destination process in the sender proc struct	*/
		sptr->p_sendto_e = pipc->molmsg.srcdst;

		/* copy the message in the sender's process structure	*/
		memcpy((void*)&sptr->messbuf, (void*)&pipc->molmsg.mnxmsg, sizeof(message));

		/* Process is now blocked.  Put in on the destination's queue. */
		xpp = dptr->p_caller_q;	
		while (xpp != NIL_PROC) 
			xpp = xpp->p_q_link;	
		xpp = sptr;			
		sptr->p_q_link = NIL_PROC;	
		} 
	
	return(OK);
}


/*----------------------------------------------------------*/
/*			mol_mini_receive					*/
/* RECEIVE request received						*/
/*----------------------------------------------------------*/
int mol_mini_receive(ipc_t *pipc)
{
	struct kproc *sptr, *dptr, *xpp;
  	int src_e;
	int rcode;
	proc_nr_t src_p,dst_p;

OLDEBUG("code=%X spid=%d seq=%d p_nr=%d p_endpoint=%d srcdst=%d m_source=%d\n",
                pipc->molmsg.code,
                pipc->molmsg.spid,
                pipc->molmsg.seq,
                pipc->molmsg.p_nr,
                pipc->molmsg.p_endpoint,
                pipc->molmsg.srcdst,
                pipc->molmsg.mnxmsg.m_source);
	
	/* Check the receiver's endpoint 			*/
	dst_p = check_endpoint(pipc->molmsg.p_endpoint);
	if( dst_p == NONE )
		MOLERROR("Bad receiver endpoint rcode=%d\n",dst_p);
	dptr = &kproc[dst_p+NR_TASKS];

	/* Check if the receiver is a registered process */
	rcode = check_registered(dptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks for valid received sequence 		*/
	rcode = check_sequence(dptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks if the sender == receiver			*/
	rcode = check_sameproc(dptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks if the receiver process is NOTREADY	*/
	rcode = check_notready(dptr, pipc);
	if( rcode != OK) return(rcode);

	src_e = pipc->molmsg.srcdst;
OLDEBUG("src_e=%d\n",src_e);

	if( src_e != ANY )
		{
		/* Checks for a valid wanted sender					*/
		src_p = check_endpoint(src_e);
		if( src_p == NONE )
			MOLERROR("Bad source endpoint rcode=%d\n",src_p);
		sptr = &kproc[src_p+NR_TASKS];
		/* Check if the sender is a registered process */
		rcode = check_registered(sptr, pipc);
		if( rcode != OK) 
			MOLERROR("sender is not registered rcode=%d\n",rcode);
		}
	else
		{
		/*	Special treatament for ANY 					*/
		sptr = NIL_PROC;
		src_p = ANY;
		}
	
	/* searchs receiver queue to find a message that match		*/
	xpp = dptr->p_caller_q;
    	while (xpp != NIL_PROC) 
		{  
	    	if (src_e == ANY || src_p == xpp->p_nr) 
			{
OLDEBUG("Sender waiting: src_p=%d\n", src_p);
			/* A message that matchs was finded 			*/
			/* prepare the MoL message to send to the receiver	*/
			pipc->molmsg.code = (RECEIVE | ACKNOWLEDGE) ;
			pipc->molmsg.seq  = dptr->kseq;
			pipc->molmsg.spid = kpid;

			/* copy the Minix message from the senders buffer	*/
			memcpy( &pipc->molmsg.mnxmsg, &sptr->messbuf,  sizeof(message));

			/* Sends the message  to the receiver			*/
			rcode = svr_send(pipc);
			if( rcode != OK)
				MOLERROR("svr_send to RECEIVER rcode=%d\n",rcode);

			/* Unblock the sender						*/
			xpp->p_rts_flags &= ~SENDING;	
			if ( xpp->p_rts_flags == 0)
				{
				/* copy the sender's socket address from the process' slot table 	*/
				memcpy(&pipc->addr,&sptr->ipc_addr,(sizeof(struct sockaddr)));
	
				/* prepare the MoL message to send to the sender*/
				pipc->molmsg.code = (SEND | ACKNOWLEDGE) ;
				pipc->molmsg.seq  = sptr->kseq;
				pipc->molmsg.spid = kpid;

				/* Sends the acknowledge to the sender		*/
				rcode = svr_send(pipc);
				if( rcode != OK)
					MOLERROR("svr_send to SENDER rcode=%d\n",rcode);
				}
			xpp = xpp->p_q_link;
			return(OK);				
			}
		else
			xpp = xpp->p_q_link;		
    		}

OLDEBUG("Sender not waiting: src_p=%d\n", src_p);

	/* If the sender is not waiting to send, then block the receiver	*/
	dptr->p_rts_flags |= RECEIVING;

	/* sets the wanted sender process into the receiver's process slot*/
	dptr->p_getfrom_e = src_e;

	return (OK);
}


/*----------------------------------------------------------*/
/*			mol_mini_sendrec					*/
/* SENDREC request received						*/
/*----------------------------------------------------------*/
int mol_mini_sendrec(ipc_t *pipc)
{
	struct kproc *sptr, *dptr, *xpp;
	int src_e,dst_e;
	int rcode;
	proc_nr_t src_p, dst_p;

OLDEBUG("code=%X spid=%d seq=%d p_nr=%d p_endpoint=%d srcdst=%d m_source=%d\n",
                pipc->molmsg.code,
                pipc->molmsg.spid,
                pipc->molmsg.seq,
                pipc->molmsg.p_nr,
                pipc->molmsg.p_endpoint,
                pipc->molmsg.srcdst,
                pipc->molmsg.mnxmsg.m_source);
		
	/* Check sender's endpoint			 	*/
	src_p = check_endpoint(pipc->molmsg.p_endpoint);
	if( src_p == NONE )
		MOLERROR("Bad source/destination endpoint rcode=%d\n",src_p);
	sptr = &kproc[src_p+NR_TASKS];

	/* Check if the sender is a registered process 	*/
	rcode = check_registered(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks for valid received sequence 		*/
	rcode = check_sequence(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks if the sender == destination		*/
	rcode = check_sameproc(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks if the sender process is NOTREADY	*/
	rcode = check_notready(sptr, pipc);
	if( rcode != OK) return(rcode);

	dst_e = pipc->molmsg.srcdst;
	dst_p = check_endpoint(dst_e);
	if( dst_p == NONE )
		MOLERROR("Bad source/destination endpoint rcode=%d\n",dst_p);
	dptr = &kproc[dst_p+NR_TASKS];
		
	/* Check if the destination is a registered process */
	rcode = check_registered(dptr, pipc);
	if( rcode != OK) return(rcode);

	src_e = pipc->molmsg.mnxmsg.m_source;
	if ( (dptr->p_rts_flags & (RECEIVING | SENDING)) == RECEIVING &&
       	(dptr->p_getfrom_e == ANY  || 
         	dptr->p_getfrom_e == sptr->p_endpoint)) 
		{
		/*------------ The destination process is waiting for this message	*/
OLDEBUG("Destination is waiting: p_getfrom_e=%d\n", dptr->p_getfrom_e);

		/* blocks the caller for RECEIVING					*/
		sptr->p_rts_flags |= RECEIVING;

		/* sets the wanted sender process for the process 		*/
		sptr->p_getfrom_e = dst_e;
		
		dptr->p_rts_flags &= ~RECEIVING;	/* unblock destination 	*/

		/* the MINIX message is already in the IPC received struct 	*/
		/* send the MESSAGE to the DESTINATION				*/

		/* prepare the MOL HEADER to send to the DESTINATION		*/
		pipc->molmsg.code = (RECEIVE | ACKNOWLEDGE) ;
		pipc->molmsg.seq  = dptr->kseq;
		pipc->molmsg.spid = kpid;
OLDEBUG("sending message to %s\n",dptr->p_name);

		/* copies the destination's socket address to the IPC struct*/
		memcpy((void*)&pipc->addr, (void*)&dptr->ipc_addr, sizeof(struct sockaddr));
OLDEBUG("Minix message m_type=%d\n",pipc->molmsg.mnxmsg.m_type);

/* BORRAR	memcpy((void*)&dptr->messbuf, (void*)&pipc->molmsg.mnxmsg, sizeof(message)); */

		/* Send the message to the destination				*/
		rcode = svr_send(pipc);
		if( rcode != OK)
			MOLERROR("svr_send rcode=%d\n",rcode);

		if ( dptr->p_rts_flags != 0)
			MOLPRINT("DESTINATION flags = %X\n", dptr->p_rts_flags );
		}
	else
		{
		/*-- The destination process is NOT waiting for this message*/

OLDEBUG("Destination is not waiting: p_getfrom_e=%d\n", dptr->p_getfrom_e);
		/* block the sender							*/
		sptr->p_rts_flags |= (SENDING | RECEIVING) ;

		/* set the wanted destination process				*/
		sptr->p_sendto_e = pipc->molmsg.srcdst;

		/* copy the message in the process structure			*/
		memcpy( &sptr->messbuf, &pipc->molmsg.mnxmsg, sizeof(message));

		/* Process is now blocked.  Put in on the destination's queue. */
		xpp = dptr->p_caller_q;
		while (xpp != NIL_PROC) 
			xpp = xpp->p_q_link;	
		xpp = sptr;
		sptr->p_q_link = NIL_PROC;
		}

	return(OK);
}

/*----------------------------------------------------------*/
/*			mol_mini_notify					*/
/* NOTIFY request received						*/
/*----------------------------------------------------------*/
int mol_mini_notify(ipc_t *pipc)
{
	struct kproc *sptr, *dptr, *xpp;
	int rcode;
	proc_nr_t src_p, dst_p;

OLDEBUG("code=%X spid=%d seq=%d p_nr=%d p_endpoint=%d srcdst=%d m_source=%d\n",
                pipc->molmsg.code,
                pipc->molmsg.spid,
                pipc->molmsg.seq,
                pipc->molmsg.p_nr,
                pipc->molmsg.p_endpoint,
                pipc->molmsg.srcdst,
                pipc->molmsg.mnxmsg.m_source);

	/* Check sender's endpoint			 	*/
	src_p = check_endpoint(pipc->molmsg.p_endpoint);
	if( src_p == NONE )
		MOLERROR("Bad sender endpoint rcode=%d\n",src_p);
	sptr = &kproc[src_p+NR_TASKS];

	/* Check if the sender is a registered process 	*/
	rcode = check_registered(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks for valid received sequence 		*/
	rcode = check_sequence(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks if the sender == destination		*/
	rcode = check_sameproc(sptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks if the sender process is NOTREADY	*/
	rcode = check_notready(sptr, pipc);
	if( rcode != OK) return(rcode);

	dst_p = check_endpoint(pipc->molmsg.srcdst);
	if( dst_p == NONE )
		MOLERROR("Bad destination endpoint rcode=%d\n",dst_p);
	dptr = &kproc[dst_p+NR_TASKS];
	
	/* Check if the destination is a registered process */
	rcode = check_registered(dptr, pipc);
	if( rcode != OK) return(rcode);

	if ( (dptr->p_rts_flags & (RECEIVING | SENDING)) == RECEIVING &&
       	(dptr->p_getfrom_e == ANY  || 
         	dptr->p_getfrom_e == sptr->p_endpoint)) 
		{
		/*------------ The destination process is waiting for this message	*/
OLDEBUG("Destination waiting: p_getfrom_e=%d\n", dptr->p_getfrom_e);

		dptr->p_rts_flags &= ~RECEIVING;	/* unblock Destination 	*/

		/* the MINIX message is already in the IPC received struct 	*/

		/* prepare the MOL HEADER to send to the DESTINATION	*/
		pipc->molmsg.code = (RECEIVE | ACKNOWLEDGE) ;
		pipc->molmsg.seq  = dptr->kseq;
		pipc->molmsg.spid = kpid;
		pipc->molmsg.mnxmsg.m_source = sptr->p_endpoint;
		pipc->molmsg.mnxmsg.m_type = NOTIFY_FROM(src_p);
		pipc->molmsg.mnxmsg.NOTIFY_TIMESTAMP = get_uptime();
/* ATENTI, produce SEGMENTATION FAULT
		pipc->molmsg.mnxmsg.NOTIFY_ARG = dptr->p_priv->s_int_pending;
		dptr->p_priv->s_int_pending = 0;			
*/
		/* copies the destination's socket address to the IPC struct	*/
		memcpy((void*)&pipc->addr, (void*)&dptr->ipc_addr, (sizeof(struct sockaddr)));

		/* send the MESSAGE to the destination					*/
		rcode = svr_send(pipc);
		if( rcode != OK)
			MOLERROR("svr_send rcode=%d\n",rcode);
		}
	else
		{
OLDEBUG("Destination NOT waiting: p_getfrom_e=%d src_p=%d\n", dptr->p_getfrom_e, src_p);
/*
		src_id = priv(sptr)->s_id;
  		set_sys_bit(priv(dptr)->s_notify_pending, src_id);
*/
		}

	return(OK);
}

/*----------------------------------------------------------*/
/*			check_endpoint					*/
/* Searchs for a process						*/
/*----------------------------------------------------------*/
proc_nr_t check_endpoint(int endpoint)
{
	proc_nr_t p_nr;

	p_nr = _ENDPOINT_P(endpoint); /* convert endpoint to process number */
OLDEBUG(" p_nr=%d endpoint=%d \n",p_nr,endpoint);

	if (p_nr < (-NR_TASKS) || p_nr > NR_PROCS)
		MOLERROR("out of range endpoint rcode=%X\n",NONE);

	if( kproc[p_nr+NR_TASKS].p_rts_flags == SLOT_FREE)
		MOLERROR("invalid (FREE) process slot rcode=%X\n",NONE);

OLDEBUG("OK\n");	
	return(p_nr);
}

/*----------------------------------------------------------*/
/*			check_registered					*/
/* Check if it is a registered process				*/
/*----------------------------------------------------------*/
int check_registered(struct kproc *pptr, ipc_t *pipc)
{
	int rcode;

	if ( pptr == NIL_PROC)
		{
	    	pipc->molmsg.code = EMOLBADSRCDST;
		rcode = svr_send(pipc);
		if( rcode != OK )
			MOLERROR("svr_send rcode=%d",rcode);  
		MOLERROR("process unregistered rcode=%d\n",EMOLBADSRCDST);
		}

OLDEBUG("OK\n");	
	return(OK);
}

/*----------------------------------------------------------*/
/*			check_sequence					*/
/* Check the received sequence number				*/
/*----------------------------------------------------------*/
int check_sequence(struct kproc *pptr, ipc_t *pipc)
{
	int rcode;

	if( pipc->molmsg.seq != pptr->pseq)
		{
OLDEBUG("bad seq # spid=%d seq=%d pseq=%d\n",
	pipc->molmsg.spid,
	pipc->molmsg.seq,
	pptr->pseq); 

	      pipc->molmsg.code = EMOLRANGE;
		rcode = svr_send(pipc);
		if( rcode != OK )
			MOLERROR("svr_send rcode=%d",rcode);
		MOLERROR("bad sequence number; rcode=%d\n",EMOLRANGE);
		}
	pptr->kseq = pptr->pseq++;

OLDEBUG("OK\n");	
	return(OK);
}

/*----------------------------------------------------------*/
/*			check_sameproc					*/
/* Check if source == destination					*/
/*----------------------------------------------------------*/
int check_sameproc(struct kproc *pptr, ipc_t *pipc)
{
	int rcode;

	/* Checks if source == destination		*/
	if(pipc->molmsg.srcdst == pipc->molmsg.mnxmsg.m_source)
		{
OLDEBUG("source=destination spid=%d srcdst=%d m_source=%d\n",
	pipc->molmsg.spid,
	pipc->molmsg.srcdst,
	pipc->molmsg.mnxmsg.m_source); 
		pipc->molmsg.code = EMOLBADSRCDST;
		rcode = svr_send(pipc);
		if( rcode != OK )
			MOLERROR("svr_send rcode=%d",rcode);
		MOLERROR(" source=destination: rcode=%d\n",EMOLBADSRCDST);
		}

OLDEBUG("OK\n");	
	return(OK);
}

/*----------------------------------------------------------*/
/*			check_notready					*/
/* Check sender not in ready state					*/
/*----------------------------------------------------------*/
int check_notready(struct kproc *pptr, ipc_t *pipc)
{
	int rcode;

	/* Checks if the sender process is EMOLNOTREADY		*/
	if(pptr->p_rts_flags != 0)
		{
		MOLPRINT("spid=%d p_nr=%d p_rts_flags=%X\n",
			pipc->molmsg.spid,
			pipc->molmsg.p_nr,
			pptr->p_rts_flags); 
	    pipc->molmsg.code = EMOLNOTREADY;
		rcode = svr_send(pipc);
		if( rcode != OK )
			MOLERROR("svr_send rcode=%d",rcode);
		MOLERROR(" not ready; rcode=%d\n",EMOLNOTREADY);
		}

OLDEBUG("OK\n");	
	return(OK);
}


		